package com.songcha.library_common.ui.view;

import android.content.Context;
import android.util.AttributeSet;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.graphics.Rect;
import android.view.MotionEvent;
import android.view.ViewGroup;
import android.view.animation.TranslateAnimation;
import android.widget.LinearLayout;



public class VerticalOverScrollLayout extends LinearLayout {

    private static final int ANIM_TIME = 300;

    private RecyclerView childView;

    private Rect original = new Rect();

    private boolean isMoved = false;

    private float startYpos;

    //auto bounce height on slide end
    private static final int AUTO_BOUNCE_HEIHT=200;

    /**
     * damping ratio
     */
    private static final float DAMPING_COEFFICIENT = 0.5f;

    private boolean isBounce = false;

    private ScrollListener mScrollListener;

    public VerticalOverScrollLayout(Context context) {
        this(context, null);
    }

    public VerticalOverScrollLayout(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public VerticalOverScrollLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        childView = (RecyclerView) getChildAt(0);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);
        original.set(childView.getLeft(), childView.getTop(), childView.getRight(), childView.getBottom());
    }

    public void setScrollListener(ScrollListener listener) {
        mScrollListener = listener;
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                startYpos = ev.getY();
            case MotionEvent.ACTION_MOVE:
                int scrollYpos = (int) (ev.getY() - startYpos);

                boolean canPUllDown=canPullDown();
                boolean canPullUp=canPullUp();
                //boolean pullDown = scrollYpos > 0 && canPullDown();
                //boolean pullUp = scrollYpos < 0 && canPullUp();

                //Log.i("aaa",canPUllDown+","+canPullUp);

                if (scrollYpos > 0 && canPUllDown || scrollYpos < 0 && canPullUp) {
                    cancelChild(ev);
                    int offset = (int) (scrollYpos * DAMPING_COEFFICIENT);
                    childView.layout(original.left, original.top + offset, original.right, original.bottom + offset);
                    if (mScrollListener != null) {
                        mScrollListener.onScroll();
                    }
                    isMoved = true;
                    isBounce = true;
                    return true;
                } else {
                    startYpos = ev.getY();
                    isMoved = false;
                    isBounce = false;
                    return super.dispatchTouchEvent(ev);
                }
            case MotionEvent.ACTION_UP:
                if (isMoved) {
                    recoverLayout();
                }
                return isBounce || super.dispatchTouchEvent(ev);
            default:
                return true;
        }
    }

    /**
     *
     * @param ev event
     */
    private void cancelChild(MotionEvent ev) {
        ev.setAction(MotionEvent.ACTION_CANCEL);
        super.dispatchTouchEvent(ev);
    }

    /**
     * restore location
     */
    private void recoverLayout() {
        TranslateAnimation anim = new TranslateAnimation(0, 0, childView.getTop() - original.top, 0);
        anim.setDuration(ANIM_TIME);
        childView.startAnimation(anim);
        childView.layout(original.left, original.top, original.right, original.bottom);
        isMoved = false;
    }



    /**
     * determine whether can pull up
     *
     * @return
     */
    private boolean canPullDown() {
        int firstVisiblePosition = ((LinearLayoutManager) childView.getLayoutManager()).findFirstVisibleItemPosition();
        int lastVisiblePosition = ((LinearLayoutManager) childView.getLayoutManager()).findLastVisibleItemPosition();
        final int lastItemPosition = childView.getAdapter().getItemCount() - 1;
        if(lastItemPosition<0) return false;

        boolean canScroll=false;

        //index is only effect in visibility area
        int lastIndex=lastVisiblePosition-firstVisiblePosition;

        //determine can slide or not
        int childViewHeight=childView.getBottom()-childView.getTop();
        int marginBottom=((MarginLayoutParams)childView.getChildAt(lastIndex).getLayoutParams()).bottomMargin;

        if(childView.getChildAt(lastIndex).getBottom()+marginBottom > childViewHeight || lastVisiblePosition<lastItemPosition){
            canScroll=true;
        }

        if(canScroll){
            if(childView.getAdapter().getItemCount()==0){
                return false;
            }
            if (firstVisiblePosition != 0) {
                return false;
            }
            if(childView.getChildAt(0).getTop()>=0){
                return true;
            }
            return false;
        }
        return false;
    }

    /**
     * determine whether can pull down
     *
     * @return
     */
    private boolean canPullUp() {
        int firstVisiblePosition = ((LinearLayoutManager) childView.getLayoutManager()).findFirstVisibleItemPosition();
        int lastVisiblePosition = ((LinearLayoutManager) childView.getLayoutManager()).findLastVisibleItemPosition();
        final int lastItemPosition = childView.getAdapter().getItemCount() - 1;

        if(lastItemPosition<0) return false;

        //index is only effect in visibility area
        int lastIndex=lastVisiblePosition-firstVisiblePosition;
        int childViewHeight=childView.getBottom()-childView.getTop();
        //determine can slide or not
        int marginBottom=((MarginLayoutParams)childView.getChildAt(lastIndex).getLayoutParams()).bottomMargin;

        if(lastVisiblePosition==lastItemPosition && childView.getChildAt(lastIndex).getBottom()+marginBottom == childViewHeight){
            return true;
        }

        return false;
    }


    public interface ScrollListener {
        void onScroll();
    }

}
